package cn.wuxing.mediation.Filter;

import cn.wuxing.mediation.properties.GateWayProperties;
import com.alibaba.fastjson.JSONObject;
import cn.wuxing.mediation.utils.UuidUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.log4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.validation.constraints.NotNull;
import org.springframework.core.io.buffer.DataBuffer;
import java.net.URI;
import java.nio.charset.StandardCharsets;

@Slf4j
@Component
@RequiredArgsConstructor
public class AuthFilter implements GlobalFilter, Ordered {

    @Autowired
    private GateWayProperties gatewayProperties;

    private static final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String urlMethod = request.getURI().getPath();

        // 在 ServerWebExchange 中设置变量
        exchange.getAttributes().put("requestId", UuidUtil.getShortUuid());
        MDC.put("UUID", Thread.currentThread().getName());


        URI URIPath = request.getURI();
        String path = request.getPath().value();
        String method = request.getMethod().toString();
        HttpHeaders header = request.getHeaders();
        log.info("{} --------------------- 请求开始 ------------------------",exchange.getAttributes().get("requestId"));
        log.info("{} 原始请求信息：URI = {}, path = {}，method = {}，header = {}。",exchange.getAttributes().get("requestId"), URIPath, path, method, header);
        if ("POST".equals(method)) {
            return DataBufferUtils.join(exchange.getRequest().getBody())
                    .flatMap(dataBuffer -> {
                        byte[] bytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bytes);
                        String bodyString = new String(bytes, StandardCharsets.UTF_8);
                        bodyString = bodyString.replaceAll("\"ImageBase64\":\"[^\"]*\",", "");
                        log.info("{} 请求参数,不包含ImageBase64：" + bodyString,exchange.getAttributes().get("requestId"));
                        exchange.getAttributes().put("POST_BODY", bodyString);
                        DataBufferUtils.release(dataBuffer);
                        Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
                            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
                            return Mono.just(buffer);
                        });

                        ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
                                exchange.getRequest()) {
                            @NotNull
                            @Override
                            public Flux<DataBuffer> getBody() {
                                return cachedFlux;
                            }
                        };
                        return chain.filter(exchange.mutate().request(mutatedRequest)
                                .build()).doFinally(signalType -> {
                            // 请求处理完毕后清理变量
                            exchange.getAttributes().remove("requestId");
                            exchange.getAttributes().remove("hasAcquired");
                        });
                    });
        } else if ("GET".equals(method)) {
            MultiValueMap<String, String> queryParams = request.getQueryParams();
            log.info("{} 请求参数：" ,queryParams,exchange.getAttributes().get("requestId"));
            return chain.filter(exchange);
        }
        return chain.filter(exchange);
        //白名单匹配 是否放行
//        for(String pattern: gatewayProperties.getWhiteList()){
//            if(pathMatcher.matchStart(pattern, urlMethod)){
//                URI URIPath = request.getURI();
//                String path = request.getPath().value();
//                String method = request.getMethod().toString();
//                HttpHeaders header = request.getHeaders();
//                log.info("{} --------------------- 请求开始 ------------------------",exchange.getAttributes().get("requestId"));
//                log.info("{} 原始请求信息：URI = {}, path = {}，method = {}，header = {}。",exchange.getAttributes().get("requestId"), URIPath, path, method, header);
//                if ("POST".equals(method)) {
//                    return DataBufferUtils.join(exchange.getRequest().getBody())
//                            .flatMap(dataBuffer -> {
//                                byte[] bytes = new byte[dataBuffer.readableByteCount()];
//                                dataBuffer.read(bytes);
//                                String bodyString = new String(bytes, StandardCharsets.UTF_8);
//                                bodyString = bodyString.replaceAll("\"ImageBase64\":\"[^\"]*\",", "");
//                                log.info("{} 请求参数,不包含ImageBase64：" + bodyString,exchange.getAttributes().get("requestId"));
//                                exchange.getAttributes().put("POST_BODY", bodyString);
//                                DataBufferUtils.release(dataBuffer);
//                                Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
//                                    DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
//                                    return Mono.just(buffer);
//                                });
//
//                                ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(
//                                        exchange.getRequest()) {
//                                    @NotNull
//                                    @Override
//                                    public Flux<DataBuffer> getBody() {
//                                        return cachedFlux;
//                                    }
//                                };
//                                return chain.filter(exchange.mutate().request(mutatedRequest)
//                                        .build()).doFinally(signalType -> {
//                                    // 请求处理完毕后清理变量
//                                    exchange.getAttributes().remove("requestId");
//                                    exchange.getAttributes().remove("hasAcquired");
//                                });
//                            });
//                } else if ("GET".equals(method)) {
//                    MultiValueMap<String, String> queryParams = request.getQueryParams();
//                    log.info("{} 请求参数：" ,queryParams,exchange.getAttributes().get("requestId"));
//                    return chain.filter(exchange);
//                }
//                return chain.filter(exchange);
//            }
//
//        }
//        log.info("{} 接口未配置白名单：" + urlMethod);
//        //未匹配到 直接返回401
//        ServerHttpResponse response = exchange.getResponse();
//        response.setStatusCode(HttpStatus.FORBIDDEN);
//        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("status","400008");
//        jsonObject.put("errors","FAILURE");
//        jsonObject.put("code","GW-404");
//        jsonObject.put("result","The request path is not in the white list");
//        return response.writeWith(Mono.just(response.bufferFactory().wrap(jsonObject.toString().getBytes(StandardCharsets.UTF_8))));
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }
}
